package packet

import (
	"encoding/binary"
	"encoding/json"
	"fmt"
	"github.com/Unixeno/TheMoon/model"
	"github.com/Unixeno/TheMoon/pool"
	message "github.com/Unixeno/TheMoon/radio/protos"
	"io"
	"net"
	"time"
)

const (
	Version  = 0x01
	Version1 = 0x01

	SyncFlag   = 0x01 // 0=async, 1=sync
	StreamFlag = 0x02 // 1=stream

	PacketHeaderSize = 0x04
)

var BufferTooSmall = fmt.Errorf("buffer is too small to marshal message")

// 包格式：
//     0 版本号
//     1 flag
//     2 - 3 包长度

type packetHeader struct {
	Version    byte
	PacketType byte
	PayloadLen uint16
}

func (header *packetHeader) MarshalTo(buffer []byte) {
	buffer[0] = header.Version
	buffer[1] = header.PacketType
	binary.BigEndian.PutUint16(buffer[2:4], header.PayloadLen)
}

func (header *packetHeader) parseVersion1(reader io.Reader) error {
	header.Version = Version1
	buffer := make([]byte, 3)
	_, err := io.ReadFull(reader, buffer)
	if err != nil {
		return err
	}
	header.PacketType = buffer[0]
	header.PayloadLen = binary.BigEndian.Uint16(buffer[1:])
	return nil
}

func ReadPacket(conn net.Conn, timeout time.Duration) (*model.Message, error) {
	var header packetHeader
	version := make([]byte, 1)
	if _, err := conn.Read(version); err != nil {
		return nil, err
	}
	_ = conn.SetReadDeadline(time.Now().Add(timeout))
	defer conn.SetReadDeadline(time.Time{}) // 重置时间，避免影响下次接收

	switch version[0] {
	case 0x01:
		if err := header.parseVersion1(conn); err != nil {
			return nil, err
		}
	default:
		return nil, fmt.Errorf("invalid packet version %d", version[0])
	}

	buffer := pool.Fixed64KPool.Get().([]byte)

	_, err := io.ReadFull(conn, buffer[0:header.PayloadLen])
	if err != nil {
		return nil, err
	}
	modelMessage := message.Message{}
	if err := modelMessage.Unmarshal(buffer[:header.PayloadLen]); err != nil {
		return nil, err
	} else {
		sync := modelMessage.Flag&SyncFlag == SyncFlag
		stream := modelMessage.Flag&StreamFlag == StreamFlag

		result := &model.Message{
			Header: model.MessageHeader{
				ID:          modelMessage.Id,
				ParentID:    modelMessage.Parent,
				Source:      modelMessage.Source,
				Destination: modelMessage.Destination,
				Sync:        sync,
				Stream:      stream,
			},
			Content:   modelMessage.Content,
			Operation: modelMessage.Operation,
		}
		return result, nil
	}
}

func WritePacket(buffer []byte, msg *model.Message) (int, error) {

	var payload []byte
	switch msg.Content.(type) {
	case string:
		payload = []byte(msg.Content.(string))
	case []byte:
		payload = msg.Content.([]byte)
	default:
		if data, err := json.Marshal(msg.Content); err != nil {
			return 0, err
		} else {
			payload = data
		}
	}
	flag := 0
	if msg.Header.Sync {
		flag |= SyncFlag
	}
	if msg.Header.Stream {
		flag |= StreamFlag
	}
	m := message.Message{
		Id:          msg.Header.ID,
		Parent:      msg.Header.ParentID,
		Source:      msg.Header.Source,
		Destination: msg.Header.Destination,
		Content:     payload,
		Operation:   msg.Operation,
		Flag:        int32(flag),
	}
	// 检查buffer大小
	if len(buffer) < m.Size() {
		fmt.Printf("\n====>%d\n\n", m.Size())
		return 0, BufferTooSmall
	}

	header := packetHeader{
		Version:    Version,
		PacketType: 0,
		PayloadLen: uint16(m.Size()),
	}
	header.MarshalTo(buffer)
	n, err := m.MarshalTo(buffer[PacketHeaderSize:])
	return n + PacketHeaderSize, err
}
